#include "messageshowarea.h"
#include "qtimer.h"
#include "soundrecorder.h"


MessageShowArea::MessageShowArea() {
    // 设置里面的QWidget大小适度，避免不设置大小过大或过小导致看不见
    this->setWidgetResizable(true);
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    // 把垂直滚动条设置的细⼀些.
    verticalScrollBar()->setStyleSheet("QScrollBar:vertical { width: 2px; background-color: rgb(231, 231, 231); }"
                                       "QScrollBar::handle:vertical {background-color: rgb(178, 178, 178);}"
                                       "QScrollBar:vertical:hover {width: 6px;}");
    horizontalScrollBar()->setStyleSheet("QScrollBar:horizontal { height: 0px;}");
    setStyleSheet("QScrollArea { border: none;}");

    m_container = new QWidget();
    setWidget(m_container);

    // 设置布局管理器
    QVBoxLayout* layout = new QVBoxLayout();
    layout->setContentsMargins(10, 10, 10 ,10);
    layout->setSpacing(0);
    m_container->setLayout(layout);
    // 添加 消息item
#if TEST_UI
    QString text = "第三章小结与感悟"
                   " ------ 总得来说第三章作者用一个全新的视角来看待生活中的自己，观察生活中的自己，并给出了积极向上的生活方法和态度。"
                   "总得来说第三章作者用一个全新的视角来看待生活中的自己，观察生活中的自己，并给出了积极向上的生活方法和态度。";
    MessageType type = MessageType::TEXT_TYPE;
    model::UserInfo sender;
    sender.m_avatar = QIcon(":/resource/image/defaultAvatar2.jpg");
    sender.m_nickName = "left";
    sender.m_phone = "1861234567321";
    Message msg = Message::makeMessage(sender, "", type, text.toUtf8(), "none");
    for (int i = 0; i < 4; ++i) {
        msg.m_sender.m_userId = QString::number(i);
        msg.m_sender.m_nickName = QString::number(i) + " Left";
        msg.m_chatSessionId = QString::number(i);
        addMessage(true, msg);
    }
    msg.m_sender.m_nickName = QString::number(4) + " Left";
    addFrontMessage(true, msg);
    msg.m_sender.m_nickName = QString::number(5) + " Right";
    addMessage(false, msg);
#endif
}

void MessageShowArea::addMessage(bool isLeft, const Message& msg)
{
    MessageItem* item = MessageItem::createMessageItem(isLeft, msg);
    m_container->layout()->addWidget(item);
}

void MessageShowArea::addFrontMessage(bool isLeft, const Message& msg)
{
    MessageItem* item = MessageItem::createMessageItem(isLeft, msg);
    QVBoxLayout* vlayout = dynamic_cast<QVBoxLayout*>(m_container->layout());
    vlayout->insertWidget(0, item);
}

void MessageShowArea::clear()
{
    QLayoutItem* child;
    while((child = m_container->layout()->itemAt(0)) != nullptr){
        m_container->layout()->removeItem(child);  // 移除布局项
        delete child->widget();     // 删除与布局项关联的 widget
        delete child;   // 删除布局项
    }
}

void MessageShowArea::scrollToEndLater()
{
    // 把垂直滚动条的值，设置成最大值，就会移动到最低端了
    // 留出一些时间来给Qt布置画面
    QTimer* timer = new QTimer();
    connect(timer, &QTimer::timeout, this, [=]{
        int maxValue = this->verticalScrollBar()->maximum();
        verticalScrollBar()->setValue(maxValue);
        timer->stop();
        timer->deleteLater();
    });
    timer->start(500);
}

MessageItem::MessageItem(bool isLeft, const Message &msg):QWidget{nullptr}, m_isLeft(isLeft)
{
    QGridLayout* layout = new QGridLayout();
    setLayout(layout);
    layout->setContentsMargins(0, 0, 0, 5);
    layout->setVerticalSpacing(0);
    layout->setHorizontalSpacing(10);

    // 1. 头像
    m_avatar = new QPushButton();
    m_avatar->setIcon(msg.m_sender.m_avatar);
    m_avatar->setFixedSize(34, 34);
    m_avatar->setIconSize(QSize(34, 34));
    m_avatar->setCursor(Qt::PointingHandCursor);

    // 2. 标签文字
    m_nameLabel = new QLabel(msg.m_sender.m_nickName + " | " + msg.m_time);
    m_nameLabel->setStyleSheet("QLabel {color: rgb(178, 178, 178); font-size: 12px;padding: 0,0,2,0;}");
    m_nameLabel->setAlignment(Qt::AlignTop);

    // 3. 内容描述（分为 文本、图片、语言、文件）
    switch(msg.m_type){
    case model::MessageType::TEXT_TYPE:{
        m_content = createTextMessageItem(isLeft, msg.m_content);
        break;
    }
    case model::MessageType::IMAGE_TYPE:{
        m_content = createImageMessageItem(isLeft, msg.m_fileId, msg.m_content);
        break;
    }
    case model::MessageType::FILE_TYPE:{
        m_content = createFileMessageItem(isLeft, msg.m_fileId, msg.m_fileName, msg.m_content);
        break;
    }
    case model::MessageType::SPEECH_TYPE:{
        m_content = createSoundMessageItem(isLeft ,msg.m_fileId , msg.m_content);
        break;
    }
    default:{
        LOG() << "内容类型错误，未知类型";
        break;
    }
    }

    // 加入布局管理器里
    if(m_isLeft){
        layout->addWidget(m_avatar, 0, 0, 2, 1, Qt::AlignTop | Qt::AlignLeft);
        layout->addWidget(m_nameLabel, 0, 1, 1, 1, Qt::AlignTop | Qt::AlignLeft);
        layout->addWidget(m_content, 1, 1, 1, 1);
    }else{
        layout->addWidget(m_avatar, 0, 1, 2, 1, Qt::AlignTop | Qt::AlignRight);
        layout->addWidget(m_nameLabel, 0, 0, 1, 1, Qt::AlignRight);
        layout->addWidget(m_content, 1, 0, 1, 1);
    }
}

MessageItem* MessageItem::createMessageItem(bool isLeft, const Message &msg)
{
    MessageItem *item = new MessageItem(isLeft, msg);

    // 添加用户信息窗口
    connect(item->getAvatarBtn(), &QPushButton::clicked, item, [=]{
        UserInfoWidget* userinfo = new UserInfoWidget(msg.m_sender, item);
        userinfo->exec();
    });

    if(!isLeft){
        model::DataCenter* dataCenter = model::DataCenter::getInstance();
        // 更新名称
        connect(dataCenter, &model::DataCenter::changeNickNameDone, item, [=]{
            item->getnameLabel()->setText(dataCenter->getMyself()->m_nickName + " | " + msg.m_time);
        });
        // 更新头像
        connect(dataCenter, &model::DataCenter::changeAvatarDone, item, [=]{
            item->getAvatarBtn()->setIcon(dataCenter->getMyself()->m_avatar);
        });
    }

    return item;
}

QWidget *MessageItem::createTextMessageItem(bool isLeft, const QByteArray &content)
{
    QWidget* contentLabel = new MessageContentLabel(isLeft, MessageType::TEXT_TYPE, content, "", "");
    return contentLabel;
}

QWidget *MessageItem::createImageMessageItem(bool isLeft, const QString& fileID, const QByteArray &content)
{
    QWidget* imageLabel = new MessageImageLabel(isLeft, fileID, content);
    return imageLabel;
}

QWidget *MessageItem::createFileMessageItem(bool isLeft, const QString &fileID, const QString &fileName, const QByteArray &content)
{
    QWidget* fileLabel = new MessageContentLabel(isLeft, MessageType::FILE_TYPE, "[文件] "+fileName, fileID, content);
    return fileLabel;
}

QWidget *MessageItem::createSoundMessageItem(bool isLeft, const QString& fileID, const QByteArray &content)
{
    QWidget* speechLabel = new MessageContentLabel(isLeft, MessageType::SPEECH_TYPE, "[语音]", fileID, content);
    return speechLabel;
}

////////////////////////////////////////////////////////////////////////
///                             文字消息类
////////////////////////////////////////////////////////////////////////
MessageContentLabel::MessageContentLabel(bool isLeft, MessageType messageType, const QString& text,
                                         const QString& fileID, const QByteArray& content):
    m_isLeft(isLeft), m_label(new QLabel(text, this)),
    m_messageType(messageType), m_fileID(fileID), m_content(content), m_loadContentDone(false)
{
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    QFont font("微软雅黑");
    font.setPixelSize(14);
    m_label->setFont(font);
    m_label->setWordWrap(true); //  自动换行
    m_label->setStyleSheet("QLabel { padding: 0 5px; line-height: 1.2; }");
    m_label->setAlignment(Qt::AlignVCenter|Qt::AlignLeft);

    if (messageType == MessageType::TEXT_TYPE) {
        return;
    }

    // 两种情况
    // 1. fileID为空，Content有值，则是客户端发送消息给服务端
    // 2. fileID有值，Content为空，则是服务端主动发送客户端消息
    if(content.isEmpty()){
        auto dataCenter = model::DataCenter::getInstance();
        connect(dataCenter, &model::DataCenter::getSingleFileDone, this, &MessageContentLabel::updateUI);
        dataCenter->getSingleFileAsync(fileID);
    }else{
        // 不为空说明已经加载完毕了
        m_loadContentDone = true;
    }
}

void MessageContentLabel::paintEvent(QPaintEvent *event)
{
    QObject* object = this->parent();
    if (!object->isWidgetType()) {
        return;
    }
    QWidget* parent = dynamic_cast<QWidget*>(object);
    int width = parent->width() * 0.6;  // 一般取主界面的60%宽

    // qDebug() << "两者 " << parent->width() << " " << this->width();

    // 根据文字来设置绘画背景高度
    QFontMetrics mestrics(m_label->font());
    int totalWidth = mestrics.horizontalAdvance(m_label->text());  // 所有文字的宽度
    int rows = (totalWidth / (width - 40)) + 1; // - 40 是给左右两侧留下⾜够的空隙
    if (totalWidth + 40 < width) {
        // ⽂本只有⼀⾏, 且不⾜⼀⾏, 就直接调整成更⼩的宽度
        width = totalWidth + 40;
    }
    int height = rows * (m_label->font().pixelSize() * 1.2) + 20;  // 字体的高度*行数+上下间距 = 总高度

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);  // 开启抗锯齿
    QPainterPath path;

    if(m_isLeft){
        // 白色笔 和 笔刷
        painter.setPen(QPen(Qt::white, 1));
        painter.setBrush(Qt::white);

        // 矩形+小三角
        path.addRoundedRect(QRect(5, 0, width, height), 5, 5);
        path.moveTo(5, 15);
        path.lineTo(0, 20);
        path.lineTo(5, 25);
        path.closeSubpath();

        // 画
        painter.drawPath(path);
        // 调整 m_label 在绘画中的区域
        m_label->setGeometry(5, 0, width, height);
    }else{
        // 绿色 和 笔刷
        painter.setPen(QPen(QColor(137, 217, 97), 1));
        painter.setBrush(QColor(137, 217, 97));

        // 矩形+小三角
        int leftPos = this->width() - width - 10;
        int rightPos = this->width() - 10;
        path.addRoundedRect(QRect(leftPos, 0, width, height), 5, 5);
        path.moveTo(rightPos, 15);
        path.lineTo(rightPos+5, 20);
        path.lineTo(rightPos, 25);
        path.closeSubpath();

        // 画
        painter.drawPath(path);

        // 调整 m_label 在绘画中的区域
        m_label->setGeometry(leftPos, 0, width, height);
    }

    parent->setFixedHeight(height + 30);
}

void MessageContentLabel::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton){
        if(!m_loadContentDone){
            LOG() << "内容尚未加载成功";
            return ;
        }
        if(m_messageType == MessageType::FILE_TYPE){
            saveAsFile(m_content);
        }else if(m_messageType == MessageType::SPEECH_TYPE){
            m_label->setText("播放中...");
            auto sound = SoundRecorder::getInstance();
            connect(sound, &SoundRecorder::soundPlayDone, this,[=]{
                if(m_label->text() == "播放中...")
                    m_label->setText("[语音]");
            });
            sound->startPlay(m_content);
        }

    }else if(event->button() == Qt::RightButton){
        // 右键菜单
        // 可以重载 mousePressEvent 这个函数
    }
}

void MessageContentLabel::contextMenuEvent(QContextMenuEvent* event)
{
    if (m_messageType != MessageType::SPEECH_TYPE) {
        LOG() << "非语音消息暂时不支持右键菜单";
        return;
    }

    QMenu* menu = new QMenu(this);
    QAction* action = new QAction("语音转文字");
    menu->addAction(action);
    connect(action, &QAction::triggered, this, [=]{
        auto dataCenter = model::DataCenter::getInstance();
        connect(dataCenter, &model::DataCenter::speechConvertTextDone, this,
                &MessageContentLabel::speechConvertTextDone, Qt::UniqueConnection);
        dataCenter->speechConvertTextAsync(m_fileID, m_content);
    });

    menu->exec(event->globalPos());
    menu->deleteLater();
}

void MessageContentLabel::saveAsFile(const QByteArray &content)
{
    QFileInfo fileInfo(m_label->text()); // m_label 显示的是“[文件] 文件名.文件类型”
    QString filter = QString("*.%1").arg(fileInfo.suffix());
    QString path = QFileDialog::getSaveFileName(this, "另存为", QDir::homePath(), filter);
    if(path.isEmpty()){
        LOG() << "路径打开失败";
        return ;
    }
    model::writeByteArrayToFile(content, path);
}

void MessageContentLabel::updateUI(const QString& fileID, const QByteArray &content)
{
    if (fileID != m_fileID) {
        // 要修改的内容不是这个控件
        return;
    }
    m_content = content;
    m_loadContentDone = true;
    LOG() <<"文件内容加载成功";
    // update();
}

void MessageContentLabel::speechConvertTextDone(const QString &fileID, const QString &text)
{
    if(fileID != m_fileID){
        LOG() << "转换的文字不匹配当前消息文件";
        return ;
    }
    m_label->setText("[语音] | " + text);
}

////////////////////////////////////////////////////////////////////////
///                             图片消息类
////////////////////////////////////////////////////////////////////////
MessageImageLabel::MessageImageLabel(bool isLeft, const QString& fileID, const QByteArray &content)
    :m_isLeft(isLeft), m_fileID(fileID), m_imageBtn(new QPushButton(this)), m_content(content)
{
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    m_imageBtn->setStyleSheet("QPushButton { border: none;}");

    // 两种情况
    // 1. fileID为空，Content有值，则是客户端发送图片消息给服务端
    // 2. fileID有值，Content为空，则是服务端主动发送客户端消息
    if(content.isEmpty()){
        auto dataCenter = model::DataCenter::getInstance();
        connect(dataCenter, &model::DataCenter::getSingleFileDone, this, &MessageImageLabel::updateUI);
        dataCenter->getSingleFileAsync(fileID);
    }
}

void MessageImageLabel::paintEvent(QPaintEvent *event)
{
    // 2.如果 content 为空, 则需要从⽹络加载.这里先给一个默认图片格式
    QImage image;
    if(m_content.isEmpty()){
        QByteArray tmpContent = model::loadFiletoByteArray(":/resource/image/fail.jpg");
        image.loadFromData(tmpContent);
    }else{
        image.loadFromData(m_content);
    }
    QPixmap pixmap = QPixmap::fromImage(image);
    QIcon avatar(pixmap);

    // 3.等比例缩放
    // 考虑到图像的大小，限制为父布局宽度的50%
    QObject* object = this->parent();
    if (!object->isWidgetType()) {
        return;
    }
    QWidget* parent = dynamic_cast<QWidget*>(object);

    int height = 0;
    int width = parent->width() * 0.5;
    if(image.width() > width){
        height = ((double)image.height() / image.width()) * width;
    }else{
        // 图片本身不太宽, 不需要缩放.
        width = image.width();
        height = image.height();
    }
    m_imageBtn->setIcon(avatar);
    m_imageBtn->setIconSize(QSize(width, height));
    m_imageBtn->setFixedSize(width, height);

    // 设置高度，以便能够显示图片
    parent->setFixedHeight(height + 50);

    // 分左右布局，左边对方，右边自己
    if(m_isLeft){
        m_imageBtn->setGeometry(10, 0, width, height); // 设置图像位置
    }else{
        int leftPos = this->width() - width - 10;
        m_imageBtn->setGeometry(leftPos, 0, width, height); // 设置图像位置
    }
}

void MessageImageLabel::updateUI(const QString& fileID, const QByteArray &content)
{
    if (fileID != m_fileID) {
        // 需要更新的不是当前的控件.
        return;
    }
    m_content = content;
    update();
}
